home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-02-15 | 10.5 KB | 297 lines | [TEXT/MPS ] |
- UNIT StackBasedStackTranslator;
- {$N+}
- {$R-}
- {$D-}
- INTERFACE
-
- USES Types, Memory, Files, Resources, Errors, Packages, AppleEvents, ASRegistry, OSA, Components, GestaltEqu, SysEqu;
-
- FUNCTION TranslatorComponent(VAR params: ComponentParameters;
- storage: Handle): ComponentResult;
-
- IMPLEMENTATION
-
- TYPE StorageHandle = ^StoragePtr; { Our private storage }
- StoragePtr = ^StorageRecord;
- StorageRecord = RECORD
- self: ComponentInstance; { We don't need much }
- END;
- HandlePtr = ^Handle;
-
- CONST kComponentVersion = $01000100; { Our version number }
- kTranslateStack = 0; { our stack translation component selector}
-
- { Forward declarations for our private routines. }
- FUNCTION DoTranslatorCanDo(selector: INTEGER):
- ComponentResult; FORWARD;
- FUNCTION DoTranslatorClose(storageHndl: Handle;
- self: ComponentInstance): ComponentResult; FORWARD;
- FUNCTION DoTranslatorOpen(self: ComponentInstance):
- ComponentResult; FORWARD;
- FUNCTION DoTranslatorRegister: ComponentResult; FORWARD;
- FUNCTION DoTranslateStack(storageHndl: StorageHandle;
- componentSubType: OSType;
- stackFile: INTEGER;
- stackResFile: INTEGER;
- fileSpecPtr: FSSpecPtr): ComponentResult; FORWARD;
- FUNCTION FRefToFSSpec(fRefNum: INTEGER;
- VAR spec: FSSpec): OSErr; FORWARD;
- PROCEDURE MyDisposeDesc(VAR desc: AEDesc); FORWARD;
- PROCEDURE MyDisposHandle(VAR hndl: Handle); FORWARD;
-
- FUNCTION TranslatorComponent(VAR params: ComponentParameters;
- storage: Handle): ComponentResult;
- { The sole entrypoint for the component. }
- BEGIN
- IF params.what < 0 THEN { component manager values}
- CASE params.what OF
- kComponentRegisterSelect: TranslatorComponent :=
- CallComponentFunction(params,
- ComponentRoutine(@DoTranslatorRegister));
- kComponentVersionSelect: TranslatorComponent :=
- kComponentVersion;
- kComponentCanDoSelect: TranslatorComponent :=
- CallComponentFunction(params,
- ComponentRoutine(@DoTranslatorCanDo));
- kComponentCloseSelect: TranslatorComponent :=
- CallComponentFunctionWithStorage(storage,params,
- ComponentRoutine(@DoTranslatorClose));
- kComponentOpenSelect: TranslatorComponent :=
- CallComponentFunction(params,
- ComponentRoutine(@DoTranslatorOpen));
- OTHERWISE
- TranslatorComponent := badComponentSelector;
- END
- ELSE { Our component-specific routines }
- BEGIN
- IF params.what = kTranslateStack
- THEN TranslatorComponent :=
- CallComponentFunctionWithStorage(storage,
- params,ComponentRoutine(@DoTranslateStack))
- ELSE TranslatorComponent := badComponentSelector;
- END;
- END;
-
- FUNCTION DoTranslatorCanDo(selector: INTEGER): ComponentResult;
- { Called when the component is asked whether it supports a particular selector. }
- BEGIN
- IF (selector >= kComponentRegisterSelect)
- & (selector <= kTranslateStack)
- THEN DoTranslatorCanDo := 1 { valid request }
- ELSE DoTranslatorCanDo := 0; { invalid request }
- END;
-
- FUNCTION DoTranslatorClose(storageHndl: Handle;
- self: ComponentInstance): ComponentResult;
- { Called when the component is closed.
- We allocate global storage when we're opened, so we'll deallocate it here. }
- BEGIN
- MyDisposHandle(storageHndl);
- DoTranslatorClose := noErr;
- END;
-
- FUNCTION DoTranslatorOpen(self:ComponentInstance):
- ComponentResult;
- { Called when the component is opened.
- This component uses global storage, so we allocate it here. }
- VAR storageHndl: Handle;
- BEGIN
- DoTranslatorOpen := noErr;
- storageHndl := NewHandle(SizeOf(StorageRecord));
- StorageHandle(storageHndl)^^.self := self; { Remember it }
- { Tell the Component Mgr to remember our storage handle. }
- SetComponentInstanceStorage(self,storageHndl);
- END;
-
- FUNCTION DoTranslatorRegister: ComponentResult;
- { Return FALSE if it's OK to register this component. }
- VAR theWorld: SysEnvRec;
- gestaltInfo: LongInt;
- dummyResult: INTEGER;
- registerOK: BOOLEAN;
- BEGIN
- { this component needs System 7 and the Apple Event Manager. }
- dummyResult := SysEnvirons(1,theWorld);
- registerOK := (theWorld.systemVersion >= $0700) { 7.x system }
- & (Gestalt(gestaltAppleEventsAttr,gestaltInfo) = noErr)
- & BTST(gestaltInfo,gestaltAppleEventsPresent);{ AEM is present }
- DoTranslatorRegister := ORD(NOT registerOK);
- END;
-
- FUNCTION DoTranslateStack(storageHndl: StorageHandle;
- componentSubType: OSType;
- stackFile: INTEGER;
- stackResFile: INTEGER;
- fileSpecPtr: FSSpecPtr): ComponentResult;
- { Handles requests for translating stacks. }
- VAR thisComponent: Component;
- saveTopMapHndl: Handle;
- hyperPSN: ProcessSerialNumber;
- addressDesc: AEDesc;
- appleEvt: AppleEvent;
- replyEvt: AppleEvent;
- fileList: AEDescList;
- paramList: AEDescList;
- msgStr: Str255;
- compFSSpec: FSSpec;
- stackFSSpec: FSSpec;
- compResFile: INTEGER;
- result: OSErr;
- ignoreResult: OSErr;
-
- PROCEDURE CleanExit;
- { Dispose of everything we allocated before exiting. }
- BEGIN
- MyDisposeDesc(addressDesc);
- MyDisposeDesc(appleEvt);
- MyDisposeDesc(replyEvt);
- MyDisposeDesc(fileList);
- MyDisposeDesc(paramList);
-
- EXIT(DoTranslateStack);
- END;
-
- PROCEDURE CheckError(err: LongInt);
- { If an error occurred, set our return value and call CleanExit. }
- BEGIN
- IF err <> noErr THEN
- BEGIN
- DoTranslateStack := err;
- CleanExit;
- END
- END;
-
- BEGIN
- DoTranslateStack := noErr; { assume success }
-
- { Set everything to nil now that we need to allocate later. This will tell us on an
- error exit what we've allocated and what we haven't. }
- addressDesc.dataHandle := NIL;
- appleEvt. dataHandle := NIL;
- replyEvt.dataHandle := NIL;
- fileList.dataHandle := NIL;
- paramList.dataHandle := NIL;
-
- { Get FSSpec of stack to be translated. }
- CheckError(FRefToFSSpec(stackFile,stackFSSpec));
-
- { Get FSSpec of the stack that contains the HyperTalk script; this is the same
- as the FSSpec for the component resource file. }
-
- { Open the component's resource fork. }
- { We saved this little nugget in DoTranslatorOpen. }
- thisComponent := Component(storageHndl^^.self);
- IF thisComponent = NIL THEN CheckError(badComponentInstance);
- { Remember what TopMapHndl is just before we open the resource file. }
- saveTopMapHndl := HandlePtr(TopMapHndl)^;
- compResFile := OpenComponentResFile(thisComponent);
- CheckError(ResError);
- IF compResFile = -1 THEN CheckError(resFNotFound);
- { Get file spec for this component and close the resource file. }
- result := FRefToFSSpec(compResFile,compFSSpec);
- { If TopMapHndl changed when the component's resource file was opened,
- then we opened a new access path to it, and therefore we should close it. }
- IF saveTopMapHndl <> HandlePtr(TopMapHndl)^
- THEN ignoreResult := CloseComponentResFile(compResFile);
- CheckError(result);
-
- { We've got our FSSpecs; now use Apple events to make HyperCard go to the
- stack in which this component resides and, once the stack is opened,
- execute the custom 'translatestack' handler stored within the stack. }
-
- { Create address descriptor for HyperCard (which is the current process) and then
- create an "open documents" Apple event for sending to the current process. }
- hyperPSN.highLongOfPSN := 0;
- hyperPSN.lowLongOfPSN := kCurrentProcess;
- CheckError(AECreateDesc(typeProcessSerialNumber,@hyperPSN,
- SizeOf(hyperPSN),addressDesc));
- CheckError(AECreateAppleEvent(kCoreEventClass,
- kAEOpenDocuments,addressDesc,kAutoGenerateReturnID,
- kAnyTransactionID,appleEvt));
- { Create list of documents to open and put it into the direct parameter. }
- CheckError(AECreateList(NIL,0,FALSE,fileList));
- CheckError(AEPutPtr(fileList,1,typeFSS,@compFSSpec,
- SizeOf(compFSSpec)));
- CheckError(AEPutParamDesc(appleEvt,keyDirectObject,fileList));
- MyDisposeDesc(fileList); { AEPutParamDesc copied it into the Apple
- event, so we don't need this anymore. }
- { Send "open documents" Apple event to HyperCard. }
- CheckError(AESend(appleEvt,replyEvt,
- kAENoReply + kAEDontRecord,
- kAENormalPriority,kAEDefaultTimeout,NIL,NIL));
-
- MyDisposeDesc(appleEvt);
- MyDisposeDesc(replyEvt);{ desc should be null but can't hurt to make sure }
-
-
- { Now create &send our custom scripting message, "translatestack", with parameters. }
- CheckError(AECreateAppleEvent(kOSASuite,
- kASSubroutineEvent,addressDesc,
- kAutoGenerateReturnID,
- kAnyTransactionID,appleEvt));
- { Put message name into "subroutine name" parameter. }
- msgStr := 'translatestack';
- CheckError(AEPutParamPtr(appleEvt,keyASSubroutineName,
- typeChar,Ptr(ORD4(@msgStr)+1),Length(msgStr)));
- { Create list of parameters to "translate stack" message. }
- CheckError(AECreateList(NIL,0,FALSE,paramList));
- CheckError(AEPutPtr(paramList,1,typeFSS,@stackFSSpec,
- SizeOf(stackFSSpec)));
- CheckError(AEPutPtr(paramList,2,typeFSS,Ptr(fileSpecPtr),
- SizeOf(FSSpec)));
- CheckError(AEPutPtr(paramList,3,typeType,@componentSubType,
- SizeOf(componentSubType)));
- CheckError(AEPutParamDesc(appleEvt,keyDirectObject,
- paramList));
- MyDisposeDesc(paramList);
- { Send subroutine event to HyperCard }
- CheckError(AESend(appleEvt,replyEvt,
- kAENoReply+kAEDontRecord,
- kAENormalPriority,kAEDefaultTimeout,NIL,NIL));
- CleanExit;
- END;
-
- FUNCTION FRefToFSSpec(fRefNum:INTEGER; VAR spec:FSSpec):OSErr;
- { Convert a file reference number for an open access path to an FSSpec for the file.
- Returns a file spec for a currently open file. }
- VAR fcbPBlock: FCBPBRec;
- nameStr: Str255;
- result: INTEGER;
- BEGIN
- WITH fcbPBlock DO BEGIN
- ioCompletion := NIL;
- ioNamePtr := @nameStr;
- ioVRefNum := 0;
- ioRefNum := fRefNum;
- ioFCBIndx := 0;
- END;
- result := PBGetFCBInfo(@fcbPBlock,FALSE);
- IF result = noErr THEN
- BEGIN
- spec.vRefNum := fcbPBlock.ioFCBVRefNum;
- spec.parID := fcbPBlock.ioFCBParID;
- spec.name := nameStr;
- END;
- FRefToFSSpec := result;
- END;
-
- PROCEDURE MyDisposeDesc(VAR desc: AEDesc);
- { Dispose of an Apple event descriptor, if it's non-nil, and then set the dataHandle
- field to nil. Prevents accidental double-disposals of handles. }
- VAR result: OSErr;
- BEGIN
- IF desc.dataHandle <> NIL THEN result:=AEDisposeDesc(desc);
- desc.dataHandle := NIL;
- desc.descriptorType := typeNull;
- END;
-
- PROCEDURE MyDisposHandle(VAR hndl: Handle);
- { Dispose of a handle, if it's non-nil, and then set it to nil. Prevents accidental
- double-disposals of handles. }
- BEGIN
- IF hndl = NIL THEN EXIT(MyDisposHandle);
- DisposHandle(hndl);
- hndl := NIL;
- END;
-
- END.